package com.xiaotu.service.redission.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.xiaotu.dto.CommentThumbDto;
import com.xiaotu.service.redission.RedissionService;
import com.xiaotu.util.RedisKeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * @author zhangxiao
 * @create 2021-08-31 13:29
 */
@Service
@Slf4j
public class RedissionServiceImpl implements RedissionService {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Object commentThumbUp(CommentThumbDto thumbUpDto) {
        RLock rLock = null;
        Map<String, Object> res = new HashMap<>();
        Integer upCount = 0;
        Integer downCount = 0;
        Integer upOperationType = 0;
        Integer downOperationType = 0;
        try {
            rLock = redissonClient.getLock("likeLock");
            boolean tryLock = rLock.tryLock(1, 3, TimeUnit.SECONDS);
            if (tryLock) {
                String upKey = RedisKeyUtils.getIsLikedKey(thumbUpDto.getCommentId(), true);
                String downKey = RedisKeyUtils.getIsLikedKey(thumbUpDto.getCommentId(), false);
                String hashKey = RedisKeyUtils.getHashKey(thumbUpDto.getCommentId(), thumbUpDto.getUserId());
                String likeCountKey = RedisKeyUtils.getIsLikedCountKey(thumbUpDto.getCommentId(), true);
                String notLikeCountKey = RedisKeyUtils.getIsLikedCountKey(thumbUpDto.getCommentId(), false);
                CommentThumbDto downExits = (CommentThumbDto) redisTemplate.opsForHash().get(downKey, hashKey);
                if (thumbUpDto.getOperationType() == 1) {
                    if (ObjectUtil.isNotNull(downExits)) {
                        //是否存在 确认点踩
                        if (downExits.getOperationType() == 1) {
                            redisTemplate.opsForValue().increment(notLikeCountKey, -1);
                            CommentThumbDto thumbDownDto = new CommentThumbDto();
                            BeanUtil.copyProperties(thumbUpDto, thumbDownDto);
                            thumbDownDto.setOperationType(0);
                            thumbDownDto.setThumbType(0);
                            redisTemplate.opsForHash().put(downKey, hashKey, thumbDownDto);
                        }
                    }
                    upOperationType = 1;
                    redisTemplate.opsForValue().increment(likeCountKey, 1);
                } else if (thumbUpDto.getOperationType() == 0) {
                    redisTemplate.opsForValue().increment(likeCountKey, -1);
                }
                redisTemplate.opsForHash().put(upKey, hashKey, thumbUpDto);
                upCount = (Integer) redisTemplate.opsForValue().get(likeCountKey);
                Integer o = (Integer) redisTemplate.opsForValue().get(notLikeCountKey);
                if (ObjectUtil.isNotNull(o))
                    downCount = o;
            } else {
                Validator.validateTrue(Boolean.FALSE, "网络繁忙，请稍后重试!");
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //TODO:释放锁
            if (ObjectUtil.isNotNull(rLock) && rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        }
        res.put("upCount", upCount);
        res.put("downCount", downCount);
        res.put("upOperationType", upOperationType);
        res.put("downOperationType", downOperationType);
        return res;
    }

    @Override
    public Object commentThumbDown(CommentThumbDto thumbUpDto) {
        RLock rLock = null;
        Map<String, Object> res = new HashMap<>();
        Integer upCount = 0;
        Integer downCount = 0;
        Integer upOperationType = 0;
        Integer downOperationType = 0;
        try {
            rLock = redissonClient.getLock("notLikeLock");
            boolean tryLock = rLock.tryLock(1, 3, TimeUnit.SECONDS);
            if (tryLock) {
                String upKey = RedisKeyUtils.getIsLikedKey(thumbUpDto.getCommentId(), true);
                String downKey = RedisKeyUtils.getIsLikedKey(thumbUpDto.getCommentId(), false);
                String hashKey = RedisKeyUtils.getHashKey(thumbUpDto.getCommentId(), thumbUpDto.getUserId());
                String likeCountKey = RedisKeyUtils.getIsLikedCountKey(thumbUpDto.getCommentId(), true);
                String notLikeCountKey = RedisKeyUtils.getIsLikedCountKey(thumbUpDto.getCommentId(), false);
                CommentThumbDto upExits = (CommentThumbDto) redisTemplate.opsForHash().get(upKey, hashKey);
                if (thumbUpDto.getOperationType() == 1) {
                    if (ObjectUtil.isNotNull(upExits)) {
                        //是否存在 确认点赞
                        if (upExits.getOperationType() == 1) {
                            redisTemplate.opsForValue().increment(likeCountKey, -1);
                            CommentThumbDto thumbDownDto = new CommentThumbDto();
                            BeanUtil.copyProperties(thumbUpDto, thumbDownDto);
                            thumbDownDto.setOperationType(0);
                            thumbDownDto.setThumbType(0);
                            redisTemplate.opsForHash().put(upKey, hashKey, thumbDownDto);
                        }
                    }
                    downOperationType = 1;
                    redisTemplate.opsForValue().increment(notLikeCountKey, 1);
                } else if (thumbUpDto.getOperationType() == 0) {
                    redisTemplate.opsForValue().increment(notLikeCountKey, -1);
                }
                redisTemplate.opsForHash().put(downKey, hashKey, thumbUpDto);
                Integer o = (Integer) redisTemplate.opsForValue().get(likeCountKey);
                if (ObjectUtil.isNotNull(o))
                    upCount = o;
                downCount = (Integer) redisTemplate.opsForValue().get(notLikeCountKey);
            } else {
                Validator.validateTrue(Boolean.FALSE, "网络繁忙，请稍后重试!");
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //TODO:释放锁
            if (ObjectUtil.isNotNull(rLock) && rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        }
        res.put("upCount", upCount);
        res.put("downCount", downCount);
        res.put("upOperationType", upOperationType);
        res.put("downOperationType", downOperationType);
        return res;
    }

    @Override
    public CommentThumbDto commentThumbInfo(String redisKey, String mapKey) {
        return (CommentThumbDto) redisTemplate.opsForHash().get(redisKey, mapKey);
    }

    @Override
    public Integer getCommentNum(String redisKey) {
        return (Integer) redisTemplate.opsForValue().get(redisKey);
    }

    @Override
    public Object getCommentThumInfo(Integer commentId, Integer userId) {
        Map<String, Object> res = new HashMap<>();
        Integer upCount = getCommentNum(RedisKeyUtils.getIsLikedCountKey(commentId, true));
        Integer downCount = getCommentNum(RedisKeyUtils.getIsLikedCountKey(commentId, false));
        Integer upOperationType = 0;
        Integer downOperationType = 0;
        CommentThumbDto up = commentThumbInfo(RedisKeyUtils.getIsLikedKey(commentId, true), RedisKeyUtils.getHashKey(commentId, userId));
        if (ObjectUtil.isNotNull(up)) {
            upOperationType = up.getOperationType();
        }
        CommentThumbDto down = commentThumbInfo(RedisKeyUtils.getIsLikedKey(commentId, false), RedisKeyUtils.getHashKey(commentId, userId));
        if (ObjectUtil.isNotNull(down)) {
            downOperationType = down.getOperationType();
        }
        res.put("upCount", upCount);
        res.put("downCount", downCount);
        res.put("upOperationType", upOperationType);
        res.put("downOperationType", downOperationType);
        res.put("commentId", commentId);
        return res;
    }
}
